+2000-11-20 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtktextview.c, gtk/gtktextlayout.c, gtk/gtktextchild.c,
+ gtk/testtext.c: Semi-finish widget embedding. Need guffaw
+ scrolling to be implemented in GDK to finish. Also, right now
+ we just size_allocate all children on every layout change,
+ which is pretty lame. Test commented out of testtext.c,
+ until it works better.
+
2000-11-20 Alexander Larsson <alla@lysator.liu.se>
* gdk/linux-fb/gdkdrawable-fb2.c:
+2000-11-20 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtktextview.c, gtk/gtktextlayout.c, gtk/gtktextchild.c,
+ gtk/testtext.c: Semi-finish widget embedding. Need guffaw
+ scrolling to be implemented in GDK to finish. Also, right now
+ we just size_allocate all children on every layout change,
+ which is pretty lame. Test commented out of testtext.c,
+ until it works better.
+
2000-11-20 Alexander Larsson <alla@lysator.liu.se>
* gdk/linux-fb/gdkdrawable-fb2.c:
+2000-11-20 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtktextview.c, gtk/gtktextlayout.c, gtk/gtktextchild.c,
+ gtk/testtext.c: Semi-finish widget embedding. Need guffaw
+ scrolling to be implemented in GDK to finish. Also, right now
+ we just size_allocate all children on every layout change,
+ which is pretty lame. Test commented out of testtext.c,
+ until it works better.
+
2000-11-20 Alexander Larsson <alla@lysator.liu.se>
* gdk/linux-fb/gdkdrawable-fb2.c:
+2000-11-20 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtktextview.c, gtk/gtktextlayout.c, gtk/gtktextchild.c,
+ gtk/testtext.c: Semi-finish widget embedding. Need guffaw
+ scrolling to be implemented in GDK to finish. Also, right now
+ we just size_allocate all children on every layout change,
+ which is pretty lame. Test commented out of testtext.c,
+ until it works better.
+
2000-11-20 Alexander Larsson <alla@lysator.liu.se>
* gdk/linux-fb/gdkdrawable-fb2.c:
+2000-11-20 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtktextview.c, gtk/gtktextlayout.c, gtk/gtktextchild.c,
+ gtk/testtext.c: Semi-finish widget embedding. Need guffaw
+ scrolling to be implemented in GDK to finish. Also, right now
+ we just size_allocate all children on every layout change,
+ which is pretty lame. Test commented out of testtext.c,
+ until it works better.
+
2000-11-20 Alexander Larsson <alla@lysator.liu.se>
* gdk/linux-fb/gdkdrawable-fb2.c:
+2000-11-20 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtktextview.c, gtk/gtktextlayout.c, gtk/gtktextchild.c,
+ gtk/testtext.c: Semi-finish widget embedding. Need guffaw
+ scrolling to be implemented in GDK to finish. Also, right now
+ we just size_allocate all children on every layout change,
+ which is pretty lame. Test commented out of testtext.c,
+ until it works better.
+
2000-11-20 Alexander Larsson <alla@lysator.liu.se>
* gdk/linux-fb/gdkdrawable-fb2.c:
+2000-11-20 Havoc Pennington <hp@redhat.com>
+
+ * gtk/gtktextview.c, gtk/gtktextlayout.c, gtk/gtktextchild.c,
+ gtk/testtext.c: Semi-finish widget embedding. Need guffaw
+ scrolling to be implemented in GDK to finish. Also, right now
+ we just size_allocate all children on every layout change,
+ which is pretty lame. Test commented out of testtext.c,
+ until it works better.
+
2000-11-20 Alexander Larsson <alla@lysator.liu.se>
* gdk/linux-fb/gdkdrawable-fb2.c:
seg = _gtk_widget_segment_new ();
+ tree = seg->body.child.tree = gtk_text_iter_get_btree (iter);
+
insert_pixbuf_or_widget_segment (iter, seg);
- tree = seg->body.child.tree;
-
if (tree->child_anchor_table == NULL)
tree->child_anchor_table = g_hash_table_new (NULL, NULL);
GtkWidget *child)
{
g_return_if_fail (widget_segment->type = >k_text_child_type);
- g_return_if_fail (widget_segment->body.child.tree != NULL);
widget_segment->body.child.widgets =
g_slist_remove (widget_segment->body.child.widgets,
{
g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
g_return_if_fail (GTK_IS_WIDGET (child));
- g_return_if_fail (_gtk_anchored_child_get_layout (child) != NULL);
-
- gtk_text_child_anchor_queue_resize (anchor,
- _gtk_anchored_child_get_layout (child));
+
+ if (_gtk_anchored_child_get_layout (child))
+ {
+ gtk_text_child_anchor_queue_resize (anchor,
+ _gtk_anchored_child_get_layout (child));
+ }
_gtk_anchored_child_set_layout (child, NULL);
GtkTextLineSegment *seg;
g_return_if_fail (GTK_IS_TEXT_CHILD_ANCHOR (anchor));
-
+ g_return_if_fail (GTK_IS_TEXT_LAYOUT (layout));
+
seg = anchor->segment;
- g_return_if_fail (seg->body.child.tree != NULL);
+ if (seg->body.child.tree == NULL)
+ return NULL;
gtk_text_buffer_get_iter_at_child_anchor (layout->buffer,
&start, anchor);
gtk_text_layout_invalidate (layout, &start, &end);
}
+void
+gtk_text_anchored_child_set_layout (GtkWidget *child,
+ GtkTextLayout *layout)
+{
+ g_return_if_fail (GTK_IS_WIDGET (child));
+ g_return_if_fail (layout == NULL || GTK_IS_TEXT_LAYOUT (layout));
+
+ _gtk_anchored_child_set_layout (child, layout);
+}
+
+
gint width, height;
GdkRectangle draw_rect;
GtkWidget *widget;
-
- /* FIXME this doesn't work at all, and remember to use
- * risen_y
- */
widget = GTK_WIDGET (shaped);
width = widget->allocation.width;
height = widget->allocation.height;
+ printf ("widget allocation at %d,%d %d x %d\n",
+ widget->allocation.x,
+ widget->allocation.y,
+ widget->allocation.width,
+ widget->allocation.height);
+
if (GTK_WIDGET_DRAWABLE (widget) &&
- gtk_widget_intersect (widget,
- &render_state->clip_rect,
- &draw_rect))
+ gdk_rectangle_intersect (&widget->allocation,
+ &render_state->clip_rect,
+ &draw_rect))
+
{
+ printf ("drawing widget area %d,%d %d x %d\n",
+ draw_rect.x,
+ draw_rect.y,
+ draw_rect.width,
+ draw_rect.height);
+
gtk_widget_draw (widget, &draw_rect);
}
height = req.height;
display->shaped_objects =
- g_slist_append (display->shaped_objects, child);
+ g_slist_append (display->shaped_objects, child);
+
break;
}
}
}
+static gboolean
+is_shape (PangoLayoutRun *run)
+{
+ GSList *tmp_list = run->item->extra_attrs;
+
+ while (tmp_list)
+ {
+ PangoAttribute *attr = tmp_list->data;
+
+ if (attr->klass->type == PANGO_ATTR_SHAPE)
+ return TRUE;
+
+ tmp_list = tmp_list->next;
+ }
+
+ return FALSE;
+}
+
static void
-allocate_child_widgets (GtkTextLayout *layout,
+allocate_child_widgets (GtkTextLayout *text_layout,
GtkTextLineDisplay *display)
{
+ GSList *shaped = display->shaped_objects;
+ PangoLayout *layout = display->layout;
+ PangoLayoutIter *iter;
-#if 0
- gtk_signal_emit (GTK_OBJECT (layout),
- signals[ALLOCATE_CHILD],
- child,
- x, y);
-#endif
+ iter = pango_layout_get_iter (layout);
+
+ do
+ {
+ PangoLayoutRun *run = pango_layout_iter_get_run (iter);
+
+ if (run && is_shape (run))
+ {
+ GObject *shaped_object = shaped->data;
+ shaped = shaped->next;
+
+ if (GTK_IS_WIDGET (shaped_object))
+ {
+ PangoRectangle extents;
+
+ /* We emit "allocate_child" with the x,y of
+ * the widget with respect to the top of the line
+ * and the left side of the buffer
+ */
+
+ pango_layout_iter_get_run_extents (iter,
+ NULL,
+ &extents);
+
+ printf ("extents at %d,%d\n", extents.x, extents.y);
+
+ gtk_signal_emit (GTK_OBJECT (text_layout),
+ signals[ALLOCATE_CHILD],
+ shaped_object,
+ PANGO_PIXELS (extents.x) + display->x_offset,
+ PANGO_PIXELS (extents.y) + display->top_margin);
+ }
+ }
+ }
+ while (pango_layout_iter_next_run (iter));
+
+ pango_layout_iter_free (iter);
}
static void
GSList *cursor_byte_offsets = NULL;
GSList *cursor_segs = NULL;
GSList *tmp_list1, *tmp_list2;
-
+ gboolean saw_widget = FALSE;
+
g_return_val_if_fail (line != NULL, NULL);
if (layout->one_display_cache)
}
else if (seg->type == >k_text_child_type)
{
+ saw_widget = TRUE;
+
add_generic_attrs (layout, &style->appearance,
seg->byte_count,
attrs, byte_offset,
layout->one_display_cache = display;
- allocate_child_widgets (layout, display);
+ if (saw_widget)
+ allocate_child_widgets (layout, display);
return display;
}
void gtk_text_child_anchor_queue_resize (GtkTextChildAnchor *anchor,
GtkTextLayout *layout);
+void gtk_text_anchored_child_set_layout (GtkWidget *child,
+ GtkTextLayout *layout);
+
void gtk_text_layout_spew (GtkTextLayout *layout);
#ifdef __cplusplus
GtkTextChildAnchor *anchor;
+ gint from_top_of_line;
+ gint from_left_of_buffer;
+
/* These are ignored if anchor != NULL */
GtkTextWindowType type;
gint x;
gtk_text_view_destroy (GtkObject *object)
{
GtkTextView *text_view;
-
+ GtkTextLayout *layout;
+
text_view = GTK_TEXT_VIEW (object);
+ layout = text_view->layout;
+
gtk_text_view_destroy_layout (text_view);
gtk_text_view_set_buffer (text_view, NULL);
}
static void
-gtk_text_view_allocate_children (GtkTextView *text_view)
+gtk_text_view_update_child_allocation (GtkTextView *text_view,
+ GtkTextViewChild *vc)
{
- GSList *tmp_list;
+ gint buffer_y;
+ GtkTextIter iter;
+ GtkAllocation allocation;
+
+ gtk_text_buffer_get_iter_at_child_anchor (get_buffer (text_view),
+ &iter,
+ vc->anchor);
+
+ gtk_text_layout_get_line_yrange (text_view->layout, &iter,
+ &buffer_y, NULL);
+
+ buffer_y += vc->from_top_of_line;
+
+ allocation.x = vc->from_left_of_buffer;
+ allocation.y = buffer_y;
+ allocation.width = vc->widget->requisition.width;
+ allocation.height = vc->widget->requisition.height;
+
+ gtk_widget_size_allocate (vc->widget, &allocation);
+}
- return;
+static void
+gtk_text_view_child_allocated (GtkTextLayout *layout,
+ GtkWidget *child,
+ gint x,
+ gint y,
+ gpointer data)
+{
+ GtkTextViewChild *vc = NULL;
+ GtkTextView *text_view = data;
+
+ /* x,y is the position of the child from the top of the line, and
+ * from the left of the buffer. We have to translate that into text
+ * window coordinates, then size_allocate the child.
+ */
+
+ vc = gtk_object_get_data (GTK_OBJECT (child),
+ "gtk-text-view-child");
+
+ g_assert (vc != NULL);
+
+ printf ("child allocated at %d,%d\n", x, y);
+
+ vc->from_left_of_buffer = x;
+ vc->from_top_of_line = y;
+
+ gtk_text_view_update_child_allocation (text_view, vc);
+}
+
+static void
+gtk_text_view_validate_children (GtkTextView *text_view)
+{
+ GSList *tmp_list;
tmp_list = text_view->children;
while (tmp_list != NULL)
gtk_text_layout_set_screen_width (text_view->layout,
SCREEN_WIDTH (text_view));
- gtk_text_view_allocate_children (text_view);
+ gtk_text_view_validate_children (text_view);
gtk_text_view_validate_onscreen (text_view);
gtk_text_view_scroll_calc_now (text_view);
if (old_height != new_height)
{
gboolean yoffset_changed = FALSE;
-
+ GSList *tmp_list;
+
if (start_y + old_height <= text_view->yoffset - text_view->first_para_pixels)
{
text_view->yoffset += new_height - old_height;
if (yoffset_changed)
gtk_adjustment_value_changed (get_vadjustment (text_view));
+
+ /* FIXME be smarter about which anchored widgets we update */
+
+ tmp_list = text_view->children;
+ while (tmp_list != NULL)
+ {
+ GtkTextViewChild *child = tmp_list->data;
+
+ if (child->anchor)
+ gtk_text_view_update_child_allocation (text_view, child);
+
+ tmp_list = g_slist_next (tmp_list);
+ }
}
gtk_text_view_scroll_calc_now (text_view);
GtkTextView *text_view;
GdkWindowAttr attributes;
gint attributes_mask;
-
+ GSList *tmp_list;
+
text_view = GTK_TEXT_VIEW (widget);
GTK_WIDGET_SET_FLAGS (text_view, GTK_REALIZED);
gtk_text_view_unrealize (GtkWidget *widget)
{
GtkTextView *text_view;
-
+ GSList *tmp_list;
+
text_view = GTK_TEXT_VIEW (widget);
if (text_view->first_validate_idle)
text_window_unrealize (text_view->bottom_window);
gtk_text_view_destroy_layout (text_view);
-
+
(* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget);
}
{
GtkTextAttributes *style;
PangoContext *ltr_context, *rtl_context;
-
+ GSList *tmp_list;
+
text_view->layout = gtk_text_layout_new ();
gtk_signal_connect (GTK_OBJECT (text_view->layout),
GTK_SIGNAL_FUNC (changed_handler),
text_view);
+ gtk_signal_connect (GTK_OBJECT (text_view->layout),
+ "allocate_child",
+ GTK_SIGNAL_FUNC (gtk_text_view_child_allocated),
+ text_view);
+
if (get_buffer (text_view))
gtk_text_layout_set_buffer (text_view->layout, get_buffer (text_view));
gtk_text_layout_set_default_style (text_view->layout, style);
gtk_text_attributes_unref (style);
+
+ /* Set layout for all anchored children */
+
+ tmp_list = text_view->children;
+ while (tmp_list != NULL)
+ {
+ GtkTextViewChild *vc = tmp_list->data;
+
+ if (vc->anchor)
+ {
+ gtk_text_anchored_child_set_layout (vc->widget,
+ text_view->layout);
+ /* vc may now be invalid! */
+ }
+
+ tmp_list = g_slist_next (tmp_list);
+ }
}
}
{
if (text_view->layout)
{
+ /* Remove layout from all anchored children */
+ GSList *tmp_list;
+
+ tmp_list = text_view->children;
+ while (tmp_list != NULL)
+ {
+ GtkTextViewChild *vc = tmp_list->data;
+
+ if (vc->anchor)
+ {
+ gtk_text_anchored_child_set_layout (vc->widget, NULL);
+ /* vc may now be invalid! */
+ }
+
+ tmp_list = g_slist_next (tmp_list);
+ }
+
gtk_text_view_stop_cursor_blink (text_view);
gtk_text_view_end_selection_drag (text_view, NULL);
vc->widget = child;
vc->anchor = anchor;
+ vc->from_top_of_line = 0;
+ vc->from_left_of_buffer = 0;
+
g_object_ref (G_OBJECT (vc->widget));
g_object_ref (G_OBJECT (vc->anchor));
vc);
gtk_text_child_anchor_register_child (anchor, child, layout);
-
+
return vc;
}
vc->widget = child;
vc->anchor = NULL;
+ vc->from_top_of_line = 0;
+ vc->from_left_of_buffer = 0;
+
g_object_ref (G_OBJECT (vc->widget));
vc->type = type;
static void close_view (View *view);
static void view_set_title (View *view);
static void view_init_menus (View *view);
+static void view_add_example_widgets (View *view);
GSList *buffers = NULL;
GSList *views = NULL;
" .. ",
" "};
-
-
void
fill_example_buffer (GtkTextBuffer *buffer)
{
GdkPixbuf *pixbuf;
int i;
char *str;
-
+ GtkTextChildAnchor *anchor;
+
/* FIXME this is broken if called twice on a buffer, since
* we try to create tags a second time.
*/
"left_margin", 20,
"right_margin", 20,
NULL);
+
+
+#if 0
+ gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
+
+ anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
+
+ g_object_ref (G_OBJECT (anchor));
+
+ g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
+ (GDestroyNotify) g_object_unref);
+#endif
pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
new_view = get_empty_view (view);
fill_example_buffer (new_view->buffer->buffer);
+
+ view_add_example_widgets (new_view);
}
static void
GtkWidget *sw;
GtkWidget *vbox;
-
+
view = g_new0 (View, 1);
views = g_slist_prepend (views, view);
view_set_title (view);
view_init_menus (view);
+
+ view_add_example_widgets (view);
gtk_widget_show_all (view->window);
return view;
}
+static void
+view_add_example_widgets (View *view)
+{
+ GtkTextChildAnchor *anchor;
+ Buffer *buffer;
+
+ return;
+
+ buffer = view->buffer;
+
+ anchor = gtk_object_get_data (GTK_OBJECT (buffer->buffer),
+ "anchor");
+
+ if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
+ {
+ GtkWidget *widget;
+
+ widget = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
+ GTK_ICON_SIZE_DIALOG);
+
+ widget = gtk_button_new_with_label ("Foo");
+
+ gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
+ widget,
+ anchor);
+
+ gtk_widget_show (widget);
+ }
+}
+
static gboolean
file_exists (const char *filename)
{
static void close_view (View *view);
static void view_set_title (View *view);
static void view_init_menus (View *view);
+static void view_add_example_widgets (View *view);
GSList *buffers = NULL;
GSList *views = NULL;
" .. ",
" "};
-
-
void
fill_example_buffer (GtkTextBuffer *buffer)
{
GdkPixbuf *pixbuf;
int i;
char *str;
-
+ GtkTextChildAnchor *anchor;
+
/* FIXME this is broken if called twice on a buffer, since
* we try to create tags a second time.
*/
"left_margin", 20,
"right_margin", 20,
NULL);
+
+
+#if 0
+ gtk_text_buffer_get_iter_at_offset (buffer, &iter, 0);
+
+ anchor = gtk_text_buffer_create_child_anchor (buffer, &iter);
+
+ g_object_ref (G_OBJECT (anchor));
+
+ g_object_set_data_full (G_OBJECT (buffer), "anchor", anchor,
+ (GDestroyNotify) g_object_unref);
+#endif
pixbuf = gdk_pixbuf_new_from_xpm_data (book_closed_xpm);
new_view = get_empty_view (view);
fill_example_buffer (new_view->buffer->buffer);
+
+ view_add_example_widgets (new_view);
}
static void
GtkWidget *sw;
GtkWidget *vbox;
-
+
view = g_new0 (View, 1);
views = g_slist_prepend (views, view);
view_set_title (view);
view_init_menus (view);
+
+ view_add_example_widgets (view);
gtk_widget_show_all (view->window);
return view;
}
+static void
+view_add_example_widgets (View *view)
+{
+ GtkTextChildAnchor *anchor;
+ Buffer *buffer;
+
+ return;
+
+ buffer = view->buffer;
+
+ anchor = gtk_object_get_data (GTK_OBJECT (buffer->buffer),
+ "anchor");
+
+ if (anchor && !gtk_text_child_anchor_get_deleted (anchor))
+ {
+ GtkWidget *widget;
+
+ widget = gtk_image_new_from_stock (GTK_STOCK_DIALOG_WARNING,
+ GTK_ICON_SIZE_DIALOG);
+
+ widget = gtk_button_new_with_label ("Foo");
+
+ gtk_text_view_add_child_at_anchor (GTK_TEXT_VIEW (view->text_view),
+ widget,
+ anchor);
+
+ gtk_widget_show (widget);
+ }
+}
+
static gboolean
file_exists (const char *filename)
{